package ar.uade.edu.fain.ad.server.util.persistence;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

import ar.uade.edu.fain.ad.server.dao.entity.AdministracionEntity;
import ar.uade.edu.fain.ad.server.dao.entity.AdministradorEntity;
import ar.uade.edu.fain.ad.server.dao.entity.AreaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.BarraEntity;
import ar.uade.edu.fain.ad.server.dao.entity.CafeteriaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.CajaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.CajeroEntity;
import ar.uade.edu.fain.ad.server.dao.entity.CartaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.CierreCajaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.CocinaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.CocineroEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ComandaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ComisionEntity;
import ar.uade.edu.fain.ad.server.dao.entity.CompraNoVentaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.CompraVentaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.DepositoCentralEntity;
import ar.uade.edu.fain.ad.server.dao.entity.DepositoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.DepositoLocalEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ElaboracionNoVentaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ElaboracionVentaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.EmpleadoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.FacturaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.IngredienteEntity;
import ar.uade.edu.fain.ad.server.dao.entity.IngresoUsuarioEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ItemDepositoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ItemFacturaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ItemOrdenCompraEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ItemRequerimientoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.LocalEntity;
import ar.uade.edu.fain.ad.server.dao.entity.MedioPagoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.MesaCompuestaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.MesaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.MesaSimpleEntity;
import ar.uade.edu.fain.ad.server.dao.entity.MovimientoStockEntity;
import ar.uade.edu.fain.ad.server.dao.entity.MozoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.NotaDevolucionEntity;
import ar.uade.edu.fain.ad.server.dao.entity.OrdenCompraEntity;
import ar.uade.edu.fain.ad.server.dao.entity.PedidoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.PlanProduccionEstrategiaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.PlatoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ProductoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ProveedorEntity;
import ar.uade.edu.fain.ad.server.dao.entity.RecetaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.RequerimientoStockEntity;
import ar.uade.edu.fain.ad.server.dao.entity.SalonEntity;
import ar.uade.edu.fain.ad.server.dao.entity.SectorEntity;
import ar.uade.edu.fain.ad.server.dao.entity.UnidadEntity;

public final class HibernateUtil {

	private static HibernateUtil instance;

	public final Class<?>[] classes = { AdministracionEntity.class,
			AdministradorEntity.class, AreaEntity.class, BarraEntity.class,
			CafeteriaEntity.class, CajaEntity.class, CajeroEntity.class,
			CartaEntity.class, CocinaEntity.class, CocineroEntity.class,
			ComandaEntity.class, ComisionEntity.class,
			CompraNoVentaEntity.class, CompraVentaEntity.class,
			DepositoCentralEntity.class, DepositoEntity.class,
			DepositoLocalEntity.class, ElaboracionNoVentaEntity.class,
			ElaboracionVentaEntity.class, EmpleadoEntity.class,
			FacturaEntity.class, IngredienteEntity.class,
			IngresoUsuarioEntity.class, ItemDepositoEntity.class,
			ItemFacturaEntity.class, ItemOrdenCompraEntity.class,
			ItemRequerimientoEntity.class, LocalEntity.class,
			MedioPagoEntity.class, MesaEntity.class, MesaSimpleEntity.class,
			MesaCompuestaEntity.class, MovimientoStockEntity.class,
			MozoEntity.class, OrdenCompraEntity.class, PedidoEntity.class,
			PlanProduccionEstrategiaEntity.class, PlatoEntity.class,
			ProductoEntity.class, ProveedorEntity.class, RecetaEntity.class,
			RequerimientoStockEntity.class, SalonEntity.class,
			SectorEntity.class, UnidadEntity.class, NotaDevolucionEntity.class,
			CierreCajaEntity.class };

	private SessionFactory sessionFactory;

	private ThreadLocal<Session> sessionHolder;

	private HibernateUtil() {
		super();
		this.sessionHolder = new ThreadLocal<Session>();
	}

	public static HibernateUtil get() {
		if (instance == null) {
			instance = new HibernateUtil();
			instance.init();
		}
		return instance;
	}

	private void init() {
		final AnnotationConfiguration configuration = new AnnotationConfiguration();
		final String overridePropertiesPath = System
				.getProperty("hibernate.properties.path");
		if (overridePropertiesPath != null) {
			final Properties properties = new Properties();
			FileInputStream is;
			try {
				is = new FileInputStream(overridePropertiesPath);
				properties.load(is);
				is.close();
				configuration.setProperties(properties);
			} catch (FileNotFoundException e) {
				System.out
						.println("La configuracion provista no se puede encontrar, "
								+ "usando defaults.");
			} catch (IOException e) {
				throw new IllegalStateException(
						"Archivo de configuracion no puede ser levantado.", e);
			}
		}
		for (Class<?> annotatedClass : classes) {
			configuration.addAnnotatedClass(annotatedClass);
		}
		this.sessionFactory = configuration.buildSessionFactory();
	}

	private SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	private ThreadLocal<Session> getSessionHolder() {
		return sessionHolder;
	}

	public synchronized Session getSession() {
		Session session = getSessionHolder().get();
		if (session == null || !session.isOpen()) {
			session = getSessionFactory().openSession();
			getSessionHolder().set(session);
		}
		return session;
	}

}
